Skip to content

KTOR-9203 Add non-blocking release function for multi-part content#5372

Open
bjhham wants to merge 2 commits intomainfrom
bjhham/dispose-blocking-fix
Open

KTOR-9203 Add non-blocking release function for multi-part content#5372
bjhham wants to merge 2 commits intomainfrom
bjhham/dispose-blocking-fix

Conversation

@bjhham
Copy link
Copy Markdown
Contributor

@bjhham bjhham commented Feb 17, 2026

Subsystem
Server, Core

Motivation
KTOR-9203 CIOMultipartDataBase: Call thread is blocked when releasing file parts since 3.2.0

Solution
Added function for releasing multi-part contents with suspend instead of blocking.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Feb 17, 2026

📝 Walkthrough

Walkthrough

PartData gained a suspendable release callback (release) and dispose was deprecated. Multipart events gained suspend fun releaseSuspend(). Implementations and call sites were updated to call release()/releaseSuspend() instead of dispose()/release() where applicable; constructors and API signatures were extended accordingly.

Changes

Cohort / File(s) Summary
PartData API
ktor-http/api/ktor-http.api, ktor-http/api/ktor-http.klib.api
Added release accessor/property and extended PartData and subclass constructors to accept a suspendable release callback; synthetic/overload signatures updated.
PartData Implementation
ktor-http/common/src/io/ktor/http/content/Multipart.kt
Primary PartData constructor now accepts release: suspend () -> Unit; dispose parameter annotated deprecated; nested items (FormItem, FileItem, BinaryItem) gain optional release param (default {}); compatibility constructors added.
MultipartEvent Suspend API
ktor-http/ktor-http-cio/api/ktor-http-cio.api, ktor-http/ktor-http-cio/api/ktor-http-cio.klib.api, ktor-http/ktor-http-cio/common/src/io/ktor/http/cio/Multipart.kt
Introduced abstract suspend fun releaseSuspend() on MultipartEvent; implemented in Preamble, MultipartPart, and Epilogue. Existing synchronous release() marked deprecated; multipart part release logic updated to use suspendable flow.
CIOMultipartDataBase Usage
ktor-http/ktor-http-cio/common/src/io/ktor/http/cio/CIOMultipartDataBase.kt
Replaced previous synchronous dispose invocations with previousPart?.release(); conversions now pass both release and releaseSuspend callbacks where applicable.
Server-side multipart handling
ktor-server/ktor-server-core/common/src/io/ktor/server/engine/DefaultTransform.kt
Switched cleanup call from part.dispose() to part.release() when processing PartData.FormItem in default transformations.
Tests and helpers
ktor-client/ktor-client-tests/.../MultiPartFormDataTest.kt, ktor-server/ktor-server-plugins/.../ContentNegotiationJvmTest.kt, ktor-server/ktor-server-tests/.../TestEngineMultipartTest.kt, ktor-server/ktor-server-tests/jvm/.../MultipartServerTest.kt
Updated tests and multipart builders to call release() (or suspend equivalents) in finally/cleanup paths instead of dispose().

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 15.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main change: adding a non-blocking (suspend) release function for multi-part content handling.
Description check ✅ Passed The description follows the template with all required sections: Subsystem (Server, Core), Motivation (referencing KTOR-9203 and the blocking issue), and Solution (adding suspend release function).
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch bjhham/dispose-blocking-fix

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
Review rate limit: 7/8 reviews remaining, refill in 7 minutes and 30 seconds.

Comment @coderabbitai help to get the list of available commands and usage tips.

@bjhham bjhham force-pushed the bjhham/dispose-blocking-fix branch from b59554c to e0bb735 Compare February 17, 2026 16:15
@bjhham bjhham force-pushed the bjhham/dispose-blocking-fix branch from e0bb735 to aa6ab25 Compare April 14, 2026 13:44
@bjhham bjhham requested a review from osipxd April 14, 2026 15:20
@bjhham bjhham marked this pull request as ready for review April 14, 2026 15:20
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (1)
ktor-http/common/src/io/ktor/http/content/Multipart.kt (1)

17-26: Update KDoc to document release instead of deprecated dispose.

The KDoc at line 18 mentions @property dispose but dispose is now deprecated. Update the documentation to reflect the new release property.

Proposed KDoc update
 /**
  * Represents a multipart/form-data entry. Could be a [FormItem] or [FileItem].
  *
  * [Report a problem](https://ktor.io/feedback/?fqname=io.ktor.http.content.PartData)
  *
- * `@property` dispose to be invoked when this part is no longer needed
+ * `@property` release suspend function to be invoked when this part is no longer needed
  * `@property` headers of this part, could be inaccurate on some engines
  */
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ktor-http/common/src/io/ktor/http/content/Multipart.kt` around lines 17 - 26,
Update the KDoc for the sealed class PartData to stop documenting the deprecated
dispose property and instead document the new suspend release property: replace
the `@property` dispose line with an `@property` release entry that describes its
purpose (a suspend function to be invoked when the part is no longer needed) and
note that dispose is deprecated and release should be used; reference the
PartData class and its release: suspend () -> Unit signature so readers can find
the correct member.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@ktor-http/api/ktor-http.api`:
- Around line 1517-1547: The public constructors for
io.ktor.http.content.PartData and nested classes (PartData$BinaryChannelItem,
PartData$BinaryItem, PartData$FileItem, PartData$FormItem) were changed to add a
Function1 `release` parameter which breaks binary compatibility; restore
compatibility by adding overload constructors that match the old signatures and
delegate to the new constructors (e.g., provide constructors without the
`release` Function1 that supply a default no-op release), or if the change is
intentional make it explicit in the API by marking it as a breaking change and
add clear migration notes in the public docs and changelog referencing the
modified symbols PartData.<init>, PartData$BinaryChannelItem.<init>,
PartData$BinaryItem.<init>, PartData$FileItem.<init>, and
PartData$FormItem.<init>.

In `@ktor-http/ktor-http-cio/common/src/io/ktor/http/cio/CIOMultipartDataBase.kt`:
- Line 35: The non-blocking cleanup is not actually wired up: update eventToData
to call event.releaseSuspend() instead of the blocking event.release(), and in
partToData when creating FormItem and FileItem supply the suspend release
callback (release = { part.releaseSuspend() }) instead of using the old
disposable lambda (dispose); this ensures previousPart?.release() will invoke
the suspend release provided by those items and removes remaining blocking calls
in eventToData and partToData.

In `@ktor-http/ktor-http-cio/common/src/io/ktor/http/cio/Multipart.kt`:
- Around line 88-91: In releaseSuspend ensure the body channel is always
discarded even if headers.await() throws: wrap the headers.await().release()
call in a try block and call body.discard() in a finally block so body.discard()
runs regardless of exceptions; update the releaseSuspend implementation (the
suspend method named releaseSuspend) to use try/finally around headers.await()
and headers.await().release() while still calling body.discard() in the finally.

---

Nitpick comments:
In `@ktor-http/common/src/io/ktor/http/content/Multipart.kt`:
- Around line 17-26: Update the KDoc for the sealed class PartData to stop
documenting the deprecated dispose property and instead document the new suspend
release property: replace the `@property` dispose line with an `@property` release
entry that describes its purpose (a suspend function to be invoked when the part
is no longer needed) and note that dispose is deprecated and release should be
used; reference the PartData class and its release: suspend () -> Unit signature
so readers can find the correct member.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 8b92734a-1156-4f5b-b41e-dbb61988a7d6

📥 Commits

Reviewing files that changed from the base of the PR and between 0a8388d and aa6ab25.

📒 Files selected for processing (12)
  • ktor-client/ktor-client-tests/common/test/io/ktor/client/tests/MultiPartFormDataTest.kt
  • ktor-http/api/ktor-http.api
  • ktor-http/api/ktor-http.klib.api
  • ktor-http/common/src/io/ktor/http/content/Multipart.kt
  • ktor-http/ktor-http-cio/api/ktor-http-cio.api
  • ktor-http/ktor-http-cio/api/ktor-http-cio.klib.api
  • ktor-http/ktor-http-cio/common/src/io/ktor/http/cio/CIOMultipartDataBase.kt
  • ktor-http/ktor-http-cio/common/src/io/ktor/http/cio/Multipart.kt
  • ktor-server/ktor-server-core/common/src/io/ktor/server/engine/DefaultTransform.kt
  • ktor-server/ktor-server-plugins/ktor-server-content-negotiation/jvm/test/ContentNegotiationJvmTest.kt
  • ktor-server/ktor-server-tests/common/test/io/ktor/tests/server/http/TestEngineMultipartTest.kt
  • ktor-server/ktor-server-tests/jvm/test/io/ktor/server/http/MultipartServerTest.kt

Comment thread ktor-http/api/ktor-http.api
Comment thread ktor-http/ktor-http-cio/common/src/io/ktor/http/cio/Multipart.kt
Copy link
Copy Markdown
Member

@osipxd osipxd left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good
I have only one concern about binary compatibility

Comment thread ktor-http/api/ktor-http.klib.api
@bjhham bjhham requested a review from osipxd April 30, 2026 10:32
@bjhham bjhham force-pushed the bjhham/dispose-blocking-fix branch from 1bde154 to 918833b Compare April 30, 2026 10:33
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
ktor-http/common/src/io/ktor/http/content/Multipart.kt (1)

23-28: ⚡ Quick win

Document the new release callback on PartData.

dispose is now deprecated, but the class KDoc still only describes the old cleanup path. Please update the public docs so callers can discover that release is the preferred lifecycle hook.

Suggested doc update
- * `@property` dispose to be invoked when this part is no longer needed
+ * `@property` dispose legacy blocking cleanup callback
+ * `@property` release suspendable cleanup callback used by the new API
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ktor-http/common/src/io/ktor/http/content/Multipart.kt` around lines 23 - 28,
Update the KDoc for the sealed class PartData to document the new suspend
release callback as the preferred cleanup lifecycle hook and mark dispose as
deprecated; specifically, revise the class-level and constructor parameter docs
to explain that release is the canonical asynchronous cleanup method to be
invoked by consumers (and may be called automatically by the framework), that
dispose remains for binary compatibility but is deprecated, and include usage
guidance and any concurrency/exception semantics for release; reference the
PartData class and its constructor parameters release and dispose when updating
the documentation.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@ktor-http/common/src/io/ktor/http/content/Multipart.kt`:
- Around line 23-28: Update the KDoc for the sealed class PartData to document
the new suspend release callback as the preferred cleanup lifecycle hook and
mark dispose as deprecated; specifically, revise the class-level and constructor
parameter docs to explain that release is the canonical asynchronous cleanup
method to be invoked by consumers (and may be called automatically by the
framework), that dispose remains for binary compatibility but is deprecated, and
include usage guidance and any concurrency/exception semantics for release;
reference the PartData class and its constructor parameters release and dispose
when updating the documentation.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 15ff66e4-7dc0-486c-940a-6872e11d8ca9

📥 Commits

Reviewing files that changed from the base of the PR and between 1bde154 and 918833b.

📒 Files selected for processing (12)
  • ktor-client/ktor-client-tests/common/test/io/ktor/client/tests/MultiPartFormDataTest.kt
  • ktor-http/api/ktor-http.api
  • ktor-http/api/ktor-http.klib.api
  • ktor-http/common/src/io/ktor/http/content/Multipart.kt
  • ktor-http/ktor-http-cio/api/ktor-http-cio.api
  • ktor-http/ktor-http-cio/api/ktor-http-cio.klib.api
  • ktor-http/ktor-http-cio/common/src/io/ktor/http/cio/CIOMultipartDataBase.kt
  • ktor-http/ktor-http-cio/common/src/io/ktor/http/cio/Multipart.kt
  • ktor-server/ktor-server-core/common/src/io/ktor/server/engine/DefaultTransform.kt
  • ktor-server/ktor-server-plugins/ktor-server-content-negotiation/jvm/test/ContentNegotiationJvmTest.kt
  • ktor-server/ktor-server-tests/common/test/io/ktor/tests/server/http/TestEngineMultipartTest.kt
  • ktor-server/ktor-server-tests/jvm/test/io/ktor/server/http/MultipartServerTest.kt
✅ Files skipped from review due to trivial changes (1)
  • ktor-server/ktor-server-tests/jvm/test/io/ktor/server/http/MultipartServerTest.kt
🚧 Files skipped from review as they are similar to previous changes (2)
  • ktor-server/ktor-server-plugins/ktor-server-content-negotiation/jvm/test/ContentNegotiationJvmTest.kt
  • ktor-client/ktor-client-tests/common/test/io/ktor/client/tests/MultiPartFormDataTest.kt

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants